import React from 'react';

import './Map.css';
import InnerParkingMapUtil from './InnerParkingMapUtil';
import MapUtil from './MapUtil';

import {routeArray} from '../../const/index';

const inndoorNavgationData = require('./data/indoor_navigation_data');

const path = routeArray;

const innerParkUtil = new InnerParkingMapUtil();

let bear = 0;

let animation = [];

export default class Map extends React.Component {
    constructor() {
        super();
        this.state = {
            map: null,
            floor: 'F1',
            floorChangeFlag: false,//让其它忽略这个事件
            showParanoma: false
        }
    }

    componentDidMount() {

        const map = MapUtil.initMap(this);

        this.setState({
            map
        });

        map.on('click', (e) => {
            let features = map.queryRenderedFeatures(e.point, {layers: ['paranoma1']});
            if (features.length > 0) {
                this.setState({
                    showParanoma: true
                })
            }
        })

        init();
        animate();
    }

    componentDidUpdate() {
        if (!this.state.floorChangeFlag) {
            if (this.props.mapState === 'reserved' || this.props.mapState === 'navigating') {
                this.state.map.setFilter('parking', ['==', 'name', this.props.selectedPark]);
                this.state.map.setLayoutProperty('path', 'visibility', 'visible');
            }

            if (this.props.mapState !== 'normal' && this.props.mapState !== 'selected') {
                MapUtil.popup.remove();
            }

            if (this.props.mapState === 'selecting_spot') {
                // 执行选择车位
                // 结束后回调 this.props.changeMapState('state')
                const map = this.state.map;
                if (!this.props.selecedSpot) {
                    innerParkUtil.addInnerParkingLayers(this.state.map);
                }

                map.on('click', (e) => {
                    if (this.props.mapState === 'selecting_spot') {
                        var features = map.queryRenderedFeatures(e.point, {layers: ['park-layer-spot1']});
                        if (features[0]) {
                            let feature = features[0];
                            let findData = inndoorNavgationData.default;
                            let _route = findData[feature.properties.space_id];

                            if (!_route) {
                                alert("此车位不可预定");
                            } else {
                                // console.log(_route);
                                innerParkUtil.setSelectedSpotStatus(this.state.map, feature.properties.space_id, 2);
                                innerParkUtil.removeInnerParkingLayers(this.state.map);
                                this.props.changeSelectedSpot(feature.properties.space_id);
                                this.props.changeMapState('selected_spot')
                            }
                        }
                    }
                });

                if(!this.props.selectedSpot) {
                    setTimeout(() => {
                        this.state.map.flyTo({
                            zoom: 18,
                            center: [106.64783, 26.621483],
                            pitch: 0,
                            bearing: 0,
                            duration: 3000,
                        });
                        //调用此方法，用于注册停车位点的选择
                        // this.parkSpotChoose();
                    }, 800)
                }    

            }

            if (this.props.mapState === 'navigating') {
                navigate(this.state.map, path, true, 16, 50, this.props.changeMapState.bind(this, 'navigated'));
            }

            // if (this.props.filter) {
            //     this.state.map.setFilter('parking', ['==', 'search-id', 1]);
            //     this.state.map.setFilter('search-point', ['==', 'search-id', 1]);
            //     this.state.map.flyTo({
            //         center: [106.6610578, 26.6079437],
            //         zoom: 15
            //     })
            // }

            if (this.props.searched) {
                setTimeout(() => {
                    this.state.map.setFilter('parking', ['==', 'search-id', 1]);
                    this.state.map.setFilter('search-point', ['==', 'search-id', 1]);
                    this.state.map.flyTo({
                        center: [106.6610578, 26.6079437],
                        zoom: 15
                    })                    
                }, 1000);
            }

            if (this.props.clearSearched) {
                this.state.map.setFilter('parking', ['==', 'search-id', 0]);
                this.state.map.setFilter('search-point', ['==', 'search-id', 0]);
                this.state.map.flyTo({
                    center: [106.645414, 26.6135198],
                    zoom: 14
                })
            }

            if (this.props.mapState === 'selecting_spot' 
                || this.props.mapState === 'selected_spot' 
                || this.props.mapState === 'indoor_navigating' 
                || this.props.mapState === 'indoor_navigated') {
                document.getElementById('floorChoose').style.display = 'block';
            }
            else {
                document.getElementById('floorChoose').style.display = 'none';
            }

            if (this.props.mapState === 'navigated') {
                innerParkUtil.addInnerParkingLayers(this.state.map);
                if (this.props.selectedSpot.length === 0) {
                    setTimeout(() => {
                        this.state.map.flyTo({
                            zoom: 18,
                            center: [106.64783, 26.621483],
                            pitch: 0,
                            bearing: 0,
                            duration: 3000,
                        });
                        //调用此方法，用于注册停车位点的选择
                        this.parkSpotChoose();
                    }, 800)
                } else {
                    setTimeout(() => {
                        this.state.map.flyTo({
                            zoom: 21.5,
                            center: [106.648789728744,26.6210668145151],
                            pitch: 45,
                            bearing: -60,
                            duration: 3000,
                        });

                        setTimeout(() => {

                            innerParkUtil.showInnerDrivingRoute(this.state.map, inndoorNavgationData.default[this.props.selectedSpot]);
                            navigate(this.state.map, inndoorNavgationData.default[this.props.selectedSpot], false, 19, 85, () => {
                                innerParkUtil.setSelectedSpotStatus(this.state.map, this.props.selectedSpot, 1);
                                this.props.changeMapState('indoor_navigated');
                                innerParkUtil.showInnerDrivingRoute(this.state.map, [[0, 0], [0, 0]]);
                            });

                        }, 3000);

                    }, 800)
                }

            }

            //室内图导航结束
            if (this.props.mapState === 'indoor_navigated') {
                //TODO 处理室内图导航结束
                console.log('导航结束');
            }
        } else {
            //TODO 显示隐藏不同的floor
            innerParkUtil.showFloor(this.state.floor, this.state.map);

            //TODO 控制完后进行状态重置,貌似有冲突，先不设置
            if (this.state.floorChangeFlag) {
                this.setState({
                    floorChangeFlag: false
                })
            }

        }
    }

    //停车点选择方法
    parkSpotChoose() {
        const map = this.state.map;

        map.on('click', (e) => {
            var features = map.queryRenderedFeatures(e.point, {layers: ['park-layer-spot1']});
            if (features[0]) {
                let feature = features[0];
                let findData = inndoorNavgationData.default;

                let _route = findData[feature.properties.space_id];
                console.log(_route);
                if (!_route) {
                    alert("此车位不可预定");
                } else {
                    console.log(_route);
                    //移动到最上层
                    map.moveLayer('position', 'poi1');
                    // //恢复两层全部展示
                    // innerParkUtil.showInnerParkingLayers(map);
                    innerParkUtil.showInnerDrivingRoute(this.state.map, _route);
                    innerParkUtil.setSelectedSpotStatus(this.state.map, feature.properties.space_id, 2);
                    navigate(this.state.map, _route, false, 19, 85, () => {
                        innerParkUtil.setSelectedSpotStatus(this.state.map, feature.properties.space_id, 1);
                        innerParkUtil.showInnerDrivingRoute(this.state.map, [[0, 0], [0, 0]]);
                        this.props.changeMapState('indoor_navigated');
                    });
                }
            }

        });


    }

    floorChange(e) {
        //console.log(e.target.value);
        this.setState({
            floor: e.target.value,
            floorChangeFlag: true
        })
    }

    // 恢复初始状态
    clear() {
        this.state.map.easeTo({
            center: this.state.map.getSource('my-position')._data.features[0].geometry.coordinates,
            zoom: 14,
            pitch: 0,
            bear: 0
        });
    }
    closeParanoma(e) {
        this.setState({
            showParanoma: false
        })
    }

    render() {
        return (
            <div id="map">
                <div id="paranoma"
                     style={{'visibility': this.state.showParanoma && this.props.mapState === 'indoor_navigated' ? 'visible' :'hidden'}}>
                    <button onClick={this.closeParanoma.bind(this)}>关闭</button>
                </div>
                <div id="floorChoose">
                    <select onChange={this.floorChange.bind(this)}>
                        <option value="F1">F1</option>
                        <option value="F2">F2</option>
                    </select>
                </div>
            </div>
        )
    }
}

function navigate(map, path, mapFlyCenter, zoom, speed, navigateEnd) {
    if (mapFlyCenter) {
        map.easeTo({
            center: [106.645414, 26.6135198]
        });
    }

    for (let i = 0; i < path.length; i++) {

        animation.push(setTimeout(move.bind(null, map, i, path, zoom, navigateEnd), i * (speed || 50)));
    }
}

function move(map, i, path, zoom, navigateEnd) {
    if (i > 0 && i < path.length - 1) {
        bear = getAngle(path[i - 1][0], path[i - 1][1], path[i][0], path[i][1], path[i + 1][0], path[i + 1][0])
        console.log(bear);
    }
    map.easeTo({
        center: path[i],
        zoom: zoom || 16,
        bearing: bear,
        pitch: 45,
        speed: 2,
    });
    map.getSource('my-position').setData({
        "type": "FeatureCollection",
        "features": [{
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": path[i]
            }
        }]
    });
    map.setLayoutProperty('position', 'icon-rotate', bear);
    if (i === path.length - 1) {
        navigateEnd();
    }
}

function getAngle(lng1, lat1, lng2, lat2, lng3, lat3) {
    const a = [lng1 - lng2, lat1 - lat2];
    const b = [lng2 - lng3, lat2 - lat3];
    const cos = (a[0] * b[0] + a[1] * b[1]) / (Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1]))
    let angle = Math.acos(cos) / Math.PI * 180;
    if (lng3 < lng1) {
        angle = -angle;
    }
    return angle;
}

/*------------------------------------------------*/

var camera, scene, renderer;

var isUserInteracting = false,
    onMouseDownMouseX = 0, onMouseDownMouseY = 0,
    lon = 0, onMouseDownLon = 0,
    lat = 0, onMouseDownLat = 0,
    phi = 0, theta = 0;


function init() {

    var container, mesh;

    container = document.getElementById('paranoma');

    camera = new window.THREE.PerspectiveCamera(75, window.innerWidth*2 / window.innerHeight, 1, 1100);
    camera.target = new window.THREE.Vector3(0, 0, 0);

    scene = new window.THREE.Scene();

    var geometry = new window.THREE.SphereBufferGeometry(500, 60, 40);
    // invert the geometry on the x-axis so that all of the faces point inward
    geometry.scale(-1, 1, 1);

    var material = new window.THREE.MeshBasicMaterial({
        map: new window.THREE.TextureLoader().load('./textures/vr.jpg')
    });

    mesh = new window.THREE.Mesh(geometry, material);

    scene.add(mesh);

    renderer = new window.THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight/2);
    container.appendChild(renderer.domElement);

   

    window.addEventListener('resize', onWindowResize, false);

}

function onWindowResize() {

    camera.aspect = window.innerWidth*2 / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight/2);

}

function onDocumentMouseDown(event) {

    event.preventDefault();

    isUserInteracting = true;

    onMouseDownMouseX = event.clientX;
    onMouseDownMouseY = event.clientY;

    onMouseDownLon = lon;
    onMouseDownLat = lat;

}

function onDocumentMouseMove(event) {

    if (isUserInteracting === true) {

        lon = ( onMouseDownMouseX - event.clientX ) * 0.1 + onMouseDownLon;
        lat = ( event.clientY - onMouseDownMouseY ) * 0.1 + onMouseDownLat;

    }

}

function onDocumentMouseUp(event) {

    isUserInteracting = false;

}

function onDocumentMouseWheel(event) {

    var fov = camera.fov + event.deltaY * 0.05;

    camera.fov = window.THREE.Math.clamp(fov, 10, 75);

    camera.updateProjectionMatrix();

}

function animate() {

    requestAnimationFrame(animate);
    update();

}

function update() {

    if (isUserInteracting === false) {

        lon += 0.2;

    }

    lat = Math.max(-85, Math.min(85, lat));
    phi = window.THREE.Math.degToRad(90 - lat);
    theta = window.THREE.Math.degToRad(lon);

    camera.target.x = 500 * Math.sin(phi) * Math.cos(theta);
    camera.target.y = 500 * Math.cos(phi);
    camera.target.z = 500 * Math.sin(phi) * Math.sin(theta);

    camera.lookAt(camera.target);

    /*
    // distortion
    camera.position.copy( camera.target ).negate();
    */

    renderer.render(scene, camera);

}